---
title: "Autocomplete"
description: "An autocomplete combines a text input with a listbox, allowing users to filter a list of options to items matching a query."
---

import {autocompleteContent} from "@/content/components/autocomplete";

# Autocomplete

An autocomplete combines a text input with a listbox, allowing users to filter a list of options to items matching a query.

<ComponentLinks component="autocomplete" reactAriaHook="useComboBox" />

---

<CarbonAd />

## Installation

<PackageManagers
  showGlobalInstallWarning
  commands={{
    cli: "npx heroui-cli@latest add autocomplete",
    npm: "npm install @heroui/autocomplete",
    yarn: "yarn add @heroui/autocomplete",
    pnpm: "pnpm add @heroui/autocomplete",
    bun: "bun add @heroui/autocomplete",
  }}
/>

## Import

HeroUI exports 3 autocomplete-related components:

- **Autocomplete**: The main component, which is a wrapper for the other components.
- **AutocompleteSection**: The component that contains a group of autocomplete items.
- **AutocompleteItem**: The component that represents a autocomplete item.

<ImportTabs
  commands={{
    main: `import {
  Autocomplete,
  AutocompleteSection,
  AutocompleteItem
} from "@heroui/react";`,
    individual: `import {
  Autocomplete,
  AutocompleteSection,
  AutocompleteItem
} from "@heroui/autocomplete";`,
  }}
/>

## Usage

<CodeDemo title="Usage" files={autocompleteContent.usage} />

### Dynamic items

Autocomplete follows the [Collection Components API](https://react-spectrum.adobe.com/react-stately/collections.html), accepting both static and dynamic collections.

- **Static**: The usage example above shows the static implementation, which can be used when the full list of options is known ahead of time.
- **Dynamic**: The example below can be used when the options come from an external data source such as an API call, or update over time.

<CodeDemo title="Dynamic items" files={autocompleteContent.dynamic} />

### Disabled

<CodeDemo title="Disabled" files={autocompleteContent.disabled} />

### Disabled Items

You can disable specific items by using the `disabledKeys` property.

<CodeDemo title="Disabled Items" files={autocompleteContent.disabledItems} />

### Required

If you pass the `isRequired` property to the autocomplete, it will have a `danger` asterisk at
the end of the label and the autocomplete will be required.

<CodeDemo title="Required" files={autocompleteContent.required} />

### Read Only

If you pass the `isReadOnly` property to the Autocomplete, the Listbox will open to display
all available options, but users won't be able to select any of the listed options.

<CodeDemo title="Read Only" files={autocompleteContent.readOnly} />

### Sizes

<CodeDemo title="Sizes" files={autocompleteContent.sizes} />

### Colors

<CodeDemo title="Colors" files={autocompleteContent.colors} />

### Variants

<CodeDemo title="Variants" files={autocompleteContent.variants} />

### Label Placements

You can change the position of the label by setting the `labelPlacement` property to `inside`, `outside` or `outside-left`.

<CodeDemo
  title="Label Placements"
  files={autocompleteContent.labelPlacements}
/>

> **Note**: If the `label` is not passed, the `labelPlacement` property will be `outside` by default.

### Start Content

You can use the `startContent` and `endContent` properties to add content to the start and end of
the autocomplete.

<CodeDemo title="Start Content" files={autocompleteContent.startContent} />

### Item Start & End Content

Since the `Autocomplete` component uses the [Listbox](/docs/components/listbox) component under the hood, you can
use the `startContent` and `endContent` properties of the `AutocompleteItem` component to add content to the start
and end of the autocomplete item.

<CodeDemo title="Item Start Content" files={autocompleteContent.itemStartContent} />

### Custom Value

By default, `Autocomplete` doesn't allow users to specify a value that doesn't exist in the list of options and will
revert the input value to the current selected value on blur. By specifying `allowsCustomValue`, this behavior is
suppressed and the user is free to enter any value within the field.

<CodeDemo title="Custom Value" files={autocompleteContent.customValue} />

### Custom Selector Icon

By default, `Autocomplete` uses a `chevron-down` icon as the selector icon which rotates when the autocomplete is open. You can
customize this icon by passing a custom one to the `selectorIcon` property.

<CodeDemo
  title="Custom Selector Icon"
  files={autocompleteContent.customSelectorIcon}
/>

> **Note**: Use the `disableSelectorIconRotation` property to disable the rotation of the icon.

### Without Scroll Shadow

Autocomplete component uses the [ScrollShadow](/docs/components/scroll-shadow) under the hood to show a shadow when the autocomplete content is scrollable.
You can disable this shadow by passing using the `scrollShadowProps` property.

<CodeDemo
  title="Without Scroll Shadow"
  files={autocompleteContent.withoutScrollShadow}
/>

> **Note**: You can also use the `showScrollIndicators` property to disable the scroll indicators.

### With Description

You can add a description to the autocomplete by passing the `description` property.

<CodeDemo title="With Description" files={autocompleteContent.description} />

### With Error Message

You can combine the `isInvalid` and `errorMessage` properties to show an invalid autocomplete.

<CodeDemo
  title="With Error Message"
  files={autocompleteContent.errorMessage}
/>

### Events

The `Autocomplete` component supports selection via mouse, keyboard, and touch. You can handle all of these
via the `onSelectionChange` prop. `Autocomplete` will pass the selected key to the onSelectionChange handler.
Additionally, ComboBox accepts an `onInputChange` prop which is triggered whenever the value is edited by the user,
whether through typing or option selection.

The example below uses `onSelectionChange` and `onInputChange` to update the selection and input value stored in
React state.

<CodeDemo title="Events" files={autocompleteContent.events} />

### Controlled

You can use the `selectedKey` and `onSelectionChange` properties to control the select value.

<CodeDemo
  title="Controlled with onSelectionChange"
  files={autocompleteContent.controlled}
/>

### Fully Controlled

By passing in `inputValue`, `selectedKey`, and `items` to the `Autocomplete` you can control exactly what your `Autocomplete` should display.

The following example shows how you would create a controlled `Autocomplete`, controlling everything from the selected value
`selectedKey` to the combobox options `items`.

We recommend using the `useFilter` hook from [@react-aria/i18n](https://react-spectrum.adobe.com/react-aria/useFilter.html#usefilter) to manage the filtering of the items.

<PackageManagers
  commands={{
    npm: "npm install @react-aria/i18n",
    yarn: "yarn add @react-aria/i18n",
    pnpm: "pnpm add @react-aria/i18n",
  }}
/>

```jsx
import {useFilter} from "@react-aria/i18n";
```

<Spacer y={4} />

<CodeDemo
  title="Fully Controlled"
  showPreview={false}
  showOpenInCodeSandbox={false}
  files={autocompleteContent.fullyControlled}
/>

> **Note**: It is important to note that you don't have to control every single aspect of a `Autocomplete`. If you decide to only control a single property of the `Autocomplete`, be sure to provide the change handler for that prop as well e.g. controlling `selectedKey` would require `onSelectionChange`.

### Custom Items

You can customize the autocomplete items by modifying the `AutocompleteItem` children.

<CodeDemo title="Custom Items" files={autocompleteContent.customItems} />

### Custom Empty Content Message

By default, a message `No results found.` will be shown if there is no result matching a query with your filter. You can customize the empty content message by modifying the `emptyContent` in `listboxProps`.

<CodeDemo
  title="Custom Empty Content Message"
  files={autocompleteContent.customEmptyContentMessage}
/>

### Custom Filtering

By default, `Autocomplete` uses a `"contains"` function from [useFilter](https://react-spectrum.adobe.com/react-aria/useFilter.html) to filter the
list of options. This can be overridden using the `defaultFilter` prop, or by using the `items` prop to control the
filtered list. When `items` is provided rather than `defaultItems`, `Autocomplete` does no filtering of its own.

The following example uses the `defaultFilter` prop to filter the list of options using a custom filter function.

<CodeDemo
  title="Fully Controlled"
  files={autocompleteContent.customFiltering}
/>

### Asynchronous Filtering

Autocomplete supports asynchronous filtering, in the example below we are using the [useAsyncList](https://react-spectrum.adobe.com/react-stately/useAsyncList.html) function
from [react-aria](https://react-spectrum.adobe.com) to handle asynchronous loading and filtering of data from a server.

<PackageManagers
  commands={{
    npm: "npm install @react-stately/data",
    yarn: "yarn add @react-stately/data",
    pnpm: "pnpm add @react-stately/data",
  }}
/>

```jsx
import {useAsyncList} from "@react-stately/data";
```

<Spacer y={2} />

<CodeDemo
  typescriptStrict={true}
  title="Asynchronous Filtering"
  showPreview={false}
  showOpenInCodeSandbox={false}
  files={autocompleteContent.asyncFiltering}
/>

### Asynchronous Loading

Autocomplete supports asynchronous loading, in the example below we are using a custom hook to fetch the [Pokemon API](https://pokeapi.co/api/v2/pokemon) data in combination with the `useInfiniteScroll` hook to load more data when the user reaches the end of the list.

The `isLoading` prop is used to show a loading indicator instead of the selector icon when the data is being fetched.

<PackageManagers
  commands={{
    npm: "npm install @heroui/use-infinite-scroll",
    yarn: "yarn add @heroui/use-infinite-scroll",
    pnpm: "pnpm add @heroui/use-infinite-scroll",
  }}
/>

```jsx
import {useInfiniteScroll} from "@heroui/use-infinite-scroll";
```

<Spacer y={2} />

<CodeDemo
  showPreview={false}
  showOpenInCodeSandbox={false}
  typescriptStrict={true}
  title="Asynchronous Loading"
  files={autocompleteContent.asyncLoadingItems}
/>

### Virtualization

Autocomplete supports virtualization, in the example below we are using the `isVirtualized` prop to enable virtualization.

<CodeDemo
  title="Virtualization"
  highlightedLines="41"
  files={autocompleteContent.virtualization}
/>

> **Note**: The virtualization strategy is based on the [@tanstack/react-virtual](https://tanstack.com/virtual/latest) package, which provides efficient rendering of large lists by only rendering items that are visible in the viewport.

#### Ten Thousand Items

Virtualization with 10,000 items.

<CodeDemo title="Ten Thousand Items" files={autocompleteContent.virtualizationTenThousand} />

#### Max Listbox Height

The `maxListboxHeight` prop is used to set the maximum height of the listbox. This is required when using virtualization. By default, it's set to `256`.

<CodeDemo title="Max Listbox Height" files={autocompleteContent.virtualizationMaxListboxHeight} />

#### Custom Item Height

The `itemHeight` prop is used to set the height of each item in the listbox. This is required when using virtualization. By default, it's set to `32`.

> **Note**: If the height of the list items differs from the default due to `startContent` or other custom content, be sure to pass the correct value to `itemHeight` to prevent layout issues.

<CodeDemo title="Custom Item Height" files={autocompleteContent.virtualizationCustomItemHeight} />

### With Sections

You can use the `AutocompleteSection` component to group autocomplete items.

<CodeDemo title="With Sections" files={autocompleteContent.sections} />

### Custom Sections Style

You can customize the sections style by using the `classNames` property of the `AutocompleteSection` component.

<CodeDemo title="Custom Sections Style" files={autocompleteContent.customSectionsStyle} />

### Customizing the Autocomplete

You can customize any slot of the autocomplete by using the `classNames` property. Autocomplete
component also provides the [popoverProps](/docs/components/popover#api), [listboxProps](/docs/components/listbox#api), [inputProps](/docs/components/input#api)
properties to customize the popover, listbox and input components.

<CodeDemo title="Custom Styles" files={autocompleteContent.customStyles} />

## Slots

- **base**: The main wrapper of the autocomplete. This wraps the input and popover components.
- **listboxWrapper**: The wrapper of the listbox. This wraps the listbox component, this slot is used on top of the scroll shadow component.
- **popoverContent**: The popover content slot. Use this to modify the popover content styles.
- **endContentWrapper**: The wrapper of the end content. This wraps the clear button and selector button.
- **clearButton**: The clear button slot.
- **selectorButton**: The selector button slot.

## Data Attributes

`Autocomplete` has the following attributes on the `base` element:

- **data-invalid**:
  When the autocomplete is invalid. Based on `isInvalid` prop.
- **data-open**:
  Indicates if the autocomplete's popover is open.

`Autocomplete` has the following attributes on the `selectorButton` element:

- **data-open**:
  Indicates if the autocomplete's popover is open.

`Autocomplete` has the following attributes on the `clearButton` element:

- **data-visible**:
  Indicates if the autocomplete's clear button is visible. By default it is visible when hovering the autocomplete and
  when the autocomplete has a value (desktop), or when the autocomplete has a value (mobile).

`AutocompleteItem` has the following attributes on the `base` element:

- **data-disabled**:
  When the autocomplete item is disabled. Based on autocomplete `disabledKeys` prop.
- **data-selected**:
  When the autocomplete item is selected. Based on autocomplete `selectedKey` prop.
- **data-hover**:
  When the autocomplete item is being hovered. Based on [useHover](https://react-spectrum.adobe.com/react-aria/useHover.html)
- **data-pressed**:
  When the autocomplete item is pressed. Based on [usePress](https://react-spectrum.adobe.com/react-aria/usePress.html)
- **data-focus**:
  When the autocomplete item is being focused. Based on [useFocusRing](https://react-spectrum.adobe.com/react-aria/useFocusRing.html).
- **data-focus-visible**:
  When the autocomplete item is being focused with the keyboard. Based on [useFocusRing](https://react-spectrum.adobe.com/react-aria/useFocusRing.html).

<Spacer y={4} />

## Accessibility

- Support for filtering a list of options by typing
- Support for selecting a single option
- Support for disabled options
- Support for groups of items in sections
- Support for custom user input values
- Support for controlled and uncontrolled options, selection, input value, and open state
- Support for custom filter functions
- Async loading and infinite scrolling support
- Support for virtualized scrolling for performance with long lists
- Exposed to assistive technology as a combobox with ARIA
- Labeling support for accessibility
- Required and invalid states exposed to assistive technology via ARIA
- Support for mouse, touch, and keyboard interactions
- Keyboard support for opening the combo box list box using the arrow keys, including automatically focusing the first or last item accordingly
- Support for opening the list box when typing, on focus, or manually
- Handles virtual clicks on the input from touch screen readers to toggle the list box
- Virtual focus management for combo box list box option navigation
- Hides elements outside the input and list box from assistive technology while the list box is open in a portal
- Custom localized announcements for option focusing, filtering, and selection using an ARIA live region to work around VoiceOver bugs
- Support for description and error message help text linked to the input via ARIA

<Spacer y={4} />

## API

### Autocomplete Props

<APITable
  data={[
    {
      attribute: "children*",
      type: "ReactNode[]",
      description: "The children to render. Usually a list of AutocompleteItem and AutocompleteSection elements.",
      default: "-"
    },
    {
      attribute: "label",
      type: "ReactNode",
      description: "The content to display as the label.",
      default: "-"
    },
    {
      attribute: "name",
      type: "string", 
      description: "The name of the input element, used when submitting an HTML form.",
      default: "-"
    },
    {
      attribute: "variant",
      type: "flat | bordered | faded | underlined",
      description: "The variant of the Autocomplete.",
      default: "flat"
    },
    {
      attribute: "color",
      type: "default | primary | secondary | success | warning | danger",
      description: "The color of the Autocomplete.",
      default: "default"
    },
    {
      attribute: "size",
      type: "sm | md | lg",
      description: "The size of the Autocomplete.",
      default: "md"
    },
    {
      attribute: "radius",
      type: "none | sm | md | lg | full",
      description: "The radius of the Autocomplete.",
      default: "-"
    },
    {
      attribute: "items",
      type: "Iterable<T>",
      description: "The list of Autocomplete items. (controlled)",
      default: "-"
    },
    {
      attribute: "defaultItems",
      type: "Iterable<T>",
      description: "The list of Autocomplete items (uncontrolled).",
      default: "-"
    },
    {
      attribute: "inputValue",
      type: "string",
      description: "The value of the Autocomplete input (controlled).",
      default: "-"
    },
    {
      attribute: "defaultInputValue",
      type: "string",
      description: "The value of the Autocomplete input (uncontrolled).",
      default: "-"
    },
    {
      attribute: "allowsCustomValue",
      type: "boolean",
      description: "Whether the Autocomplete allows a non-item matching input value to be set.",
      default: "false"
    },
    {
      attribute: "allowsEmptyCollection",
      type: "boolean",
      description: "Whether the autocomplete allows the menu to be open when the collection is empty.",
      default: "true"
    },
    {
      attribute: "shouldCloseOnBlur",
      type: "boolean",
      description: "Whether the Autocomplete should close when the input is blurred.",
      default: "true"
    },
    {
      attribute: "placeholder",
      type: "string",
      description: "Temporary text that occupies the text input when it is empty.",
      default: "-"
    },
    {
      attribute: "description",
      type: "ReactNode",
      description: "A description for the field. Provides a hint such as specific requirements for what to choose.",
      default: "-"
    },
    {
      attribute: "menuTrigger",
      type: "focus | input | manual",
      description: "The action that causes the menu to open.",
      default: "focus"
    },
    {
      attribute: "labelPlacement",
      type: "inside | outside | outside-left",
      description: "The position of the label.",
      default: "inside"
    },
    {
      attribute: "selectedKey",
      type: "React.Key",
      description: "The currently selected key in the collection (controlled).",
      default: "-"
    },
    {
      attribute: "defaultSelectedKey",
      type: "React.Key",
      description: "The initial selected key in the collection (uncontrolled).",
      default: "-"
    },
    {
      attribute: "disabledKeys",
      type: "all | React.Key[]",
      description: "The item keys that are disabled. These items cannot be selected, focused, or otherwise interacted with.",
      default: "-"
    },
    {
      attribute: "errorMessage",
      type: "ReactNode | ((v: ValidationResult) => ReactNode)",
      description: "An error message to display below the field.",
      default: "-"
    },
    {
      attribute: "validate",
      type: "(value: { inputValue: string, selectedKey: React.Key }) => ValidationError | true | null | undefined",
      description: "Validate input values when committing (e.g. on blur), and return error messages for invalid values.",
      default: "-"
    },
    {
      attribute: "validationBehavior",
      type: "native | aria",
      description: "Whether to use native HTML form validation or ARIA validation. When wrapped in a Form component, the default is `aria`. Otherwise, the default is `native`.",
      default: "native"
    },
    {
      attribute: "startContent",
      type: "ReactNode",
      description: "Element to be rendered in the left side of the Autocomplete.",
      default: "-"
    },
    {
      attribute: "endContent", 
      type: "ReactNode",
      description: "Element to be rendered in the right side of the Autocomplete.",
      default: "-"
    },
    {
      attribute: "autoFocus",
      type: "boolean",
      description: "Whether the Autocomplete should be focused on render.",
      default: "false"
    },
    {
      attribute: "defaultFilter",
      type: "(textValue: string, inputValue: string) => boolean",
      description: "The filter function used to determine if a option should be included in the Autocomplete list.",
      default: "-"
    },
    {
      attribute: "filterOptions",
      type: "Intl.CollatorOptions",
      description: "The options used to create the collator used for filtering.",
      default: "{ sensitivity: 'base'}"
    },
    {
      attribute: "maxListboxHeight",
      type: "number",
      description: "The maximum height of the listbox in pixels. Required when using virtualization.",
      default: "256"
    },
    {
      attribute: "itemHeight",
      type: "number", 
      description: "The fixed height of each item in pixels. Required when using virtualization.",
      default: "32"
    },
    {
      attribute: "isVirtualized",
      type: "boolean",
      description: "Whether to enable virtualization. By default, it's enabled when the number of items exceeds 50.",
      default: "undefined"
    },
    {
      attribute: "isReadOnly",
      type: "boolean",
      description: "Whether the Autocomplete is read only.",
      default: "false"
    },
    {
      attribute: "isRequired",
      type: "boolean",
      description: "Whether the Autocomplete is required.",
      default: "false"
    },
    {
      attribute: "isInvalid",
      type: "boolean",
      description: "Whether the Autocomplete is invalid.",
      default: "false"
    },
    {
      attribute: "isDisabled",
      type: "boolean",
      description: "Whether the Autocomplete is disabled.",
      default: "false"
    },
    {
      attribute: "fullWidth",
      type: "boolean",
      description: "Whether the input should take up the width of its parent.",
      default: "true"
    },
    {
      attribute: "selectorIcon",
      type: "ReactNode",
      description: "The icon that represents the autocomplete open state. Usually a chevron icon.",
      default: "-"
    },
    {
      attribute: "clearIcon",
      type: "ReactNode",
      description: "The icon to be used in the clear button. Usually a cross icon.",
      default: "-"
    },
    {
      attribute: "showScrollIndicators",
      type: "boolean",
      description: "Whether the scroll indicators should be shown when the listbox is scrollable.",
      default: "true"
    },
    {
      attribute: "scrollRef",
      type: "React.RefObject<HTMLElement>",
      description: "A ref to the scrollable element.",
      default: "-"
    },
    {
      attribute: "inputProps",
      type: "InputProps",
      description: "Props to be passed to the Input component.",
      default: "-"
    },
    {
      attribute: "popoverProps",
      type: "PopoverProps",
      description: "Props to be passed to the Popover component.",
      default: "-"
    },
    {
      attribute: "listboxProps",
      type: "ListboxProps",
      description: "Props to be passed to the Listbox component.",
      default: "-"
    },
    {
      attribute: "scrollShadowProps",
      type: "ScrollShadowProps",
      description: "Props to be passed to the ScrollShadow component.",
      default: "-"
    },
    {
      attribute: "selectorButtonProps",
      type: "ButtonProps",
      description: "Props to be passed to the selector button.",
      default: "-"
    },
    {
      attribute: "clearButtonProps",
      type: "ButtonProps",
      description: "Props to be passed to the clear button.",
      default: "-"
    },
    {
      attribute: "isClearable",
      type: "boolean",
      description: "Whether the clear button should be shown.",
      default: "true"
    },
    {
      attribute: "disableAnimation",
      type: "boolean",
      description: "Whether the Autocomplete should be animated.",
      default: "true"
    },
    {
      attribute: "disableSelectorIconRotation",
      type: "boolean",
      description: "Whether the select should disable the rotation of the selector icon.",
      default: "false"
    },
    {
      attribute: "classNames",
      type: "Partial<Record<'base' | 'listboxWrapper' | 'listbox' | 'popoverContent' | 'endContentWrapper' | 'clearButton' | 'selectorButton', string>>",
      description: "Allows to set custom class names for the Autocomplete slots.",
      default: "-"
    }
  ]}
/>

### Autocomplete Events

<APITable
  data={[
    {
      attribute: "onOpenChange",
      type: "(isOpen: boolean, menuTrigger?: MenuTriggerAction) => void",
      description: "Method that is called when the open state of the menu changes. Returns the new open state and the action that caused the opening of the menu.",
      default: "-"
    },
    {
      attribute: "onInputChange",
      type: "(value: string) => void",
      description: "Handler that is called when the Autocomplete input value changes.",
      default: "-"
    },
    {
      attribute: "onSelectionChange",
      type: "(key: React.Key) => void",
      description: "Handler that is called when the Autocomplete selection changes.",
      default: "-"
    },
    {
      attribute: "onFocus",
      type: "(e: FocusEvent<HTMLInputElement>) => void",
      description: "Handler that is called when the Autocomplete input is focused.",
      default: "-"
    },
    {
      attribute: "onBlur",
      type: "(e: FocusEvent<HTMLInputElement>) => void",
      description: "Handler that is called when the Autocomplete input is blurred.",
      default: "-"
    },
    {
      attribute: "onFocusChange",
      type: "(isFocused: boolean) => void",
      description: "Handler that is called when the Autocomplete input focus changes.",
      default: "-"
    },
    {
      attribute: "onKeyDown",
      type: "(e: KeyboardEvent) => void",
      description: "Handler that is called when a key is pressed.",
      default: "-"
    },
    {
      attribute: "onKeyUp",
      type: "(e: KeyboardEvent) => void",
      description: "Handler that is called when a key is released.",
      default: "-"
    },
    {
      attribute: "onClose",
      type: "() => void",
      description: "Handler that is called when the Autocomplete's Popover is closed.",
      default: "-"
    },
    {
      attribute: "onClear",
      type: "() => void",
      description: "Handler that is called when the clear button is clicked.",
      default: "-"
    }
  ]}
/>

---

### AutocompleteItem Props

Check the [ListboxItem](/docs/components/listbox#listboxitem-props) props.

### AutocompleteItem Events

Check the [ListboxItem](/docs/components/listbox#listboxitem-events) events.

### AutocompleteSection Props

Check the [ListboxSection](/docs/components/listbox#listboxsection-props) props.

---

### Types

#### Menu Trigger Action

```ts
type MenuTriggerAction = "focus" | "input" | "manual";
```
